﻿using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

namespace Lan.Extend
{
    [CustomEditor(typeof(GameObject))]
    public class GameObjectInspectorPreview : OverrideEditor
    {

        #region Model Attribute
        private string[] m_PreviewModeDesc = new string[] { "模型", "UV1", "UV2", "UV3", "UV4" };

        private int m_PreviewMode;

        /// <summary>
        /// UV颜色
        /// </summary>
        private Color m_UvColor = Color.green;

        [SerializeField] private UVPreview m_UVPreview;

        private List<Texture2D> m_Textures;

        private GUIContent m_TexContent;

        private int m_RendersCount = 0;

        #endregion

        #region Particle Attribute
        private class Styles
        {
            public GUIContent ps = new GUIContent("PS", "Show particle system preview");
            public GUIStyle preButton = "preButton";
        }

        private bool m_ShowParticlePreview;

        private bool m_ShowParticleOrModulePreview = false;

        private int m_DefaultHasPreview;

        private ParticleSystemPreview m_Preview;

        private static Styles s_Styles;

        private ParticleSystemPreview particlePreview
        {
            get
            {
                if (m_Preview == null)
                {
                    m_Preview = new ParticleSystemPreview();
                    m_Preview.SetEditor(this);
                    m_Preview.Initialize(targets);
                }
                return m_Preview;
            }
        }

        #endregion

        protected override Editor GetBaseEditor()
        {
            Editor editor = null;
            var baseType = typeof(Editor).Assembly.GetType("UnityEditor.GameObjectInspector");
            CreateCachedEditor(targets, baseType, ref editor);
            return editor;
        }

        #region Public Method
        void OnEnable()
        {
            GameObject gameObject = target as GameObject;
            if (gameObject.GetComponentsInChildren<ParticleSystem>().Length <= 0)
            {
                m_UVPreview = new UVPreview();
                m_UVPreview.OnEnable();
                if (target)
                    m_UVPreview.Add((GameObject)target, true);
                m_Textures = CollectTextures((GameObject)target);
                m_TexContent = new GUIContent("贴图");

                Renderer[] renderers = ((GameObject)target).GetComponentsInChildren<Renderer>();
                m_RendersCount = renderers.Length;

                m_ShowParticleOrModulePreview = false;
            }
            else
            {
                //Particle
                m_ShowParticlePreview = true;
                m_ShowParticleOrModulePreview = true;
            }
        }

        void OnDisable()
        {
            if (m_ShowParticleOrModulePreview)
                particlePreview.OnDestroy();
            else
            {
                if (m_UVPreview != null)
                    m_UVPreview.Release();
                m_UVPreview = null;
            }

            if (baseEditor)
                DestroyImmediate(baseEditor);
            baseEditor = null;
        }

        public override bool HasPreviewGUI()
        {
            if (m_ShowParticleOrModulePreview)
                return HasParticleSystemPreview() || HasBasePreview();
            else
            {
                if (baseEditor.HasPreviewGUI())
                    return true;
                return m_RendersCount > 0;
            }
        }

        #endregion


        #region Draw Model Preview
        //Draw Model Preview
        public override void DrawPreview(Rect previewArea)
        {
            if (m_ShowParticleOrModulePreview)
            {
                OnInteractivePreviewGUI(previewArea, new GUIStyle("PreBackground"));
                return;
            }

            GUI.Box(new Rect(previewArea.x, previewArea.y, previewArea.width, 17), string.Empty, GUI.skin.FindStyle("toolbar"));

            m_PreviewMode = GUI.Toolbar(new Rect(previewArea.x + 5, previewArea.y, 50 * 4, 17), m_PreviewMode,
                m_PreviewModeDesc, GUI.skin.FindStyle("toolbarbutton"));

            if (m_PreviewMode != 0)
            {
                m_UvColor = EditorGUI.ColorField(
                    new Rect(previewArea.x + previewArea.width - 50, previewArea.y + 2, 40, 13),
                    m_UvColor);
                if (GUI.Button(new Rect(previewArea.x + previewArea.width - 120, previewArea.y, 70, 17), m_TexContent,
                    GUI.skin.FindStyle("ToolbarDropDown")))
                {
                    DropDownTextures(new Rect(previewArea.x + previewArea.width - 120, previewArea.y, 70, 17));
                }
                if (GUI.Button(new Rect(previewArea.x + previewArea.width - 190, previewArea.y, 70, 17), "光照贴图",
                   GUI.skin.FindStyle("ToolbarDropDown")))
                {
                    DropDownLightMaps(new Rect(previewArea.x + previewArea.width - 120, previewArea.y, 70, 17));
                }
            }

            Rect previewRect = new Rect(previewArea.x, previewArea.y + 17, previewArea.width, previewArea.height - 17);
            if (m_PreviewMode == 0)
                baseEditor.DrawPreview(previewRect);
            else
            {
                m_UVPreview.DrawPreview(previewRect, m_UvColor, (UVPreview.UVIndex)(m_PreviewMode - 1), false);
            }
        }


        private List<Texture2D> CollectTextures(GameObject target)
        {
            List<Texture2D> result = new List<Texture2D>();
            MeshRenderer[] meshRenderers = target.GetComponentsInChildren<MeshRenderer>();
            SkinnedMeshRenderer[] skinnedMeshRenderers = target.GetComponentsInChildren<SkinnedMeshRenderer>();
            List<Material> mats = new List<Material>();
            for (int i = 0; i < meshRenderers.Length; i++)
            {
                if (meshRenderers[i].sharedMaterial)
                {
                    if (!mats.Contains(meshRenderers[i].sharedMaterial))
                        mats.Add(meshRenderers[i].sharedMaterial);
                }
            }
            for (int i = 0; i < skinnedMeshRenderers.Length; i++)
            {
                if (skinnedMeshRenderers[i].sharedMaterial)
                {
                    if (!mats.Contains(skinnedMeshRenderers[i].sharedMaterial))
                        mats.Add(skinnedMeshRenderers[i].sharedMaterial);
                }
            }
            if (mats.Count > 0)
            {
                MaterialProperty[] matProperties = MaterialEditor.GetMaterialProperties(mats.ToArray());
                if(matProperties != null)
                {
                    for (int i = 0; i < matProperties.Length; i++)
                    {
                        if (matProperties[i].type == MaterialProperty.PropType.Texture &&
                            matProperties[i].textureDimension == UnityEngine.Rendering.TextureDimension.Tex2D && matProperties[i].textureValue != null)
                        {
                            result.Add((Texture2D)matProperties[i].textureValue);
                        }
                    }
                }
            }
            return result;
        }

        private void DropDownTextures(Rect rect)
        {
            if (m_Textures == null || m_Textures.Count == 0)
                return;
            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("Empty"), m_TexContent.image == null, ClearTexture);
            menu.AddSeparator("");
            for (int i = 0; i < m_Textures.Count; i++)
            {
                menu.AddItem(new GUIContent(m_Textures[i].name, m_Textures[i]), m_TexContent.image == m_Textures[i],
                    SelectTexture, m_Textures[i]);
            }
            menu.DropDown(rect);
        }

        private void DropDownLightMaps(Rect rect)
        {
            if (LightmapSettings.lightmaps.Length > 0)
            {
                GenericMenu menu = new GenericMenu();
                for (int i = 0; i < LightmapSettings.lightmaps.Length; i++)
                {
                    menu.AddItem(new GUIContent("Index:" + i), false, SetLightMap, new LightMapData(i, false));
                    menu.AddItem(new GUIContent("Index:" + i + ",Directional"), false, SetLightMap,
                        new LightMapData(i, true));
                }
                menu.DropDown(rect);
            }
        }

        private void ClearTexture()
        {
            m_UVPreview.ClearTexture();
            m_TexContent = new GUIContent("贴图");
        }

        private void SelectTexture(System.Object texture)
        {
            if (texture == null)
                return;
            Texture2D tex = (Texture2D)texture;
            m_TexContent = new GUIContent(tex.name, tex);
            m_UVPreview.SetTexture(tex);
        }

        private void SetLightMap(object index)
        {
            LightMapData id = (LightMapData)index;
            m_UVPreview.SetLightMap(id.index, id.isDirectional);
        }

        private struct LightMapData
        {
            public int index;
            public bool isDirectional;

            public LightMapData(int index, bool isDirectional)
            {
                this.index = index;
                this.isDirectional = isDirectional;
            }
        }

        #endregion


        #region Draw Particle Preview
        private bool HasParticleSystemPreview()
        {
            ////如果没有导入编辑器下播放粒子动画工具  注释掉这个判断 280 281这两行
            //if (ArtTool.ArtToolsWindow.isOpenResourcesPreview)
            //    return false;
            return particlePreview.HasPreviewGUI();
        }

        private bool HasBasePreview()
        {
            if (m_DefaultHasPreview == 0)
            {
                m_DefaultHasPreview = baseEditor.HasPreviewGUI() ? 1 : -1;
            }
            return m_DefaultHasPreview == 1;
        }

        private bool IsShowParticleSystemPreview()
        {
            if (m_ShowParticleOrModulePreview)
                return HasParticleSystemPreview() && m_ShowParticlePreview;
            else
                return false;
        }

        public override GUIContent GetPreviewTitle()
        {
            return IsShowParticleSystemPreview() ? particlePreview.GetPreviewTitle() : baseEditor.GetPreviewTitle();
        }

        public override void OnPreviewGUI(Rect r, GUIStyle background)
        {
            if (IsShowParticleSystemPreview())
            {
                particlePreview.OnPreviewGUI(r, background);
            }
            else
            {
                baseEditor.OnPreviewGUI(r, background);
            }
        }

        public override void OnInteractivePreviewGUI(Rect r, GUIStyle background)
        {
            if (IsShowParticleSystemPreview())
            {
                particlePreview.OnInteractivePreviewGUI(r, background);
            }
            else
            {
                baseEditor.OnInteractivePreviewGUI(r, background);
            }
        }

        public override void OnPreviewSettings()
        {
            if (s_Styles == null)
            {
                s_Styles = new Styles();
            }
            if (HasBasePreview() && HasParticleSystemPreview())
            {
                m_ShowParticlePreview = GUILayout.Toggle(m_ShowParticlePreview, s_Styles.ps, s_Styles.preButton);
            }
            if (IsShowParticleSystemPreview())
            {
                particlePreview.OnPreviewSettings();
            }
            else
            {
                baseEditor.OnPreviewSettings();
            }
        }

        public override string GetInfoString()
        {
            return IsShowParticleSystemPreview() ? particlePreview.GetInfoString() : baseEditor.GetInfoString();
        }

        public override void ReloadPreviewInstances()
        {
            if (IsShowParticleSystemPreview())
            {
                particlePreview.ReloadPreviewInstances();
            }
            else
            {
                baseEditor.ReloadPreviewInstances();
            }
        }

        /// <summary>
        /// 需要调用 GameObjectInspector 的场景拖曳，否则无法拖动物体到 Scene 视图
        /// </summary>
        /// <param name="sceneView"></param>
        public void OnSceneDrag(SceneView sceneView)
        {
            System.Type t = baseEditor.GetType();
            MethodInfo onSceneDragMi = t.GetMethod("OnSceneDrag", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            if (onSceneDragMi != null)
            {
                onSceneDragMi.Invoke(baseEditor, new object[1] { sceneView });
            }
        }

        #endregion
    }

}
